

Berta.EditorManager.addPlugin('Textline', new Class(function() {
	
	return {
		extend: Berta.Editor,
		pluginName: 'Textline',
		
		// defaults for this particular plugin
		defaults: {
			pluginOptions: {
				newlines: false,
				// false -> no newlines are allowed with Enter character
				// true -> '<br>' is inserted
				
				tags_allowed: false
				// false 		 -> no tags (except <br> if newlines==true) are allowed
				// true 		 -> all tags are allowed (strip_tags is not executed) - DANGER DANGER!
				// <tag><tag>... -> tags that are allowed in strip_tags
				// if newlines==false, then allowed_tags shouldn't contain block tags
				
				// see defaults.pluginOptions in Berta.Editor class for inherited options
			}
		},
		
		constructor: function(options) {
			// call the parent with pluginName=null
			// Editor defaults get extended by this.defaults and then extended by options
			Berta.Editor.call(this, options);
			
			this.originalValue = this.element.html();
			this.value = this.originalValue;
		},
		
		
		//   .______    __    __  .______    __       __    ______    ////////////////////////////////////////////////////////////
		//   |   _  \  |  |  |  | |   _  \  |  |     |  |  /      |   ////////////////////////////////////////////////////////////
		//   |  |_)  | |  |  |  | |  |_)  | |  |     |  | |  ,----'   ////////////////////////////////////////////////////////////
		//   |   ___/  |  |  |  | |   _  <  |  |     |  | |  |        ////////////////////////////////////////////////////////////
		//   |  |      |  `--'  | |  |_)  | |  `----.|  | |  `----.   ////////////////////////////////////////////////////////////
		//   | _|       \______/  |______/  |_______||__|  \______|   ////////////////////////////////////////////////////////////
		
		on: /* API */ function() {
			this.element.addClass('x-editable-on');
			this.element.bind('click' + this.namespace(), this._(onElementClick));
			this.appendPlaceholderIfEmpty();
			Berta.Editor.prototype.on.call(this);
		},
		
		off: /* API */ function() {
			if(this.hasFlag(Berta.Editor.flags.EDITING)) {
				this.cancel();
			}
			this.element.removeClass('x-editable-on');
			this.element.unbind('click' + this.namespace());
			this.removePlaceholder();
			Berta.Editor.prototype.off.call(this);
		},
		
		edit: /* API */ function() {
			if(this.hasFlag(Berta.Editor.flags.ON) && !this.hasFlag(Berta.Editor.flags.EDITING)) {
				Berta.Editor.prototype.startEditing.call(this);
				this._(startEditing)();
				Berta.Editor.prototype.setPanelContext.call(this);
			}
		},
		
		save: /* API */ function() {
			if(this.hasFlag(Berta.Editor.flags.EDITING)) {
				this.value = this.getValue();// get a clened-up value
				//$.log(this.value, ', ', this.originalValue, this.value.length, ', ', this.originalValue.length);
				if(this.value != this.originalValue) this.fireChange();
				this._(stopEditing)();
				this.replacementElement.html(this.value);	// update replacement element with cleaned-up value
				Berta.Editor.prototype.stopEditing.call(this);
				Berta.Editor.prototype.save.call(this, this._(onSaveComplete));
			}
		},
		
		cancel: /* API */ function() {
			Berta.Editor.prototype.hidePanelContext.call(this);
			if(this.hasFlag(Berta.Editor.flags.EDITING)) {
				this._(stopEditing)();
			
			} else if(this.hasFlag(Berta.Editor.flags.SAVING)) {
				this.saveStop();
			
			} else {
				this.element.html(this.originalValue);
			
			}
			
			this.value = this.originalValue;
			this.fireRevert();
			this.cleanup();
		},

		
		cleanup: function() {
			if (this.replacementElement) {
				this.element.removeClass('x-hidden')
							.data(Berta.Editor.DATA_REPLACEMENT, null);
				this.replacementElement.empty().remove();
				this.replacementElement = null;
			}
			
			if(this.hasFlag(Berta.Editor.flags.DESTROYING)) {
				this.off();
			} else {
				this.appendPlaceholderIfEmpty();
			}
		},
		
		
		
		
		validate: /* override */ function() {
			Berta.Editor.prototype.validate.call(this);
			
			// when only text allowed then allowed_tags should be "<br>"
			// when html is allowed, then add the <br> only if allowed_tags is not empty (which means: all tags are allowed)
			if(this.options.newlines && this.options.tags_allowed !== true && (!this.options.tags_allowed || this.options.tags_allowed.indexOf('<br>') < 0))
				this.options.tags_allowed = this.options.tags_allowed ? (this.options.tags_allowed + '<br>') : '<br>';
		},
		
		
		getValue: function() {
			var v;
			if (this.hasFlag(Berta.Editor.flags.EDITING)) {
				if (this.options.pluginOptions.tags_allowed !== true) {
					v = (strip_tags(this.replacementElement.html(), this.options.pluginOptions.tags_allowed));
				} else {
					v = this.replacementElement.html();
				}
				
				if(editing_NBSPFixApplied && v == '&nbsp;') {
					v = '';
				}
				
			} else {
				v = this.value;
			}
			
			return v;
		}

		
	};
	
	
	
	
	//   .______   .______     __  ____    ____  ___   .___________. _______    //////////////////////////////////////////////////
	//   |   _  \  |   _  \   |  | \   \  /   / /   \  |           ||   ____|   //////////////////////////////////////////////////
	//   |  |_)  | |  |_)  |  |  |  \   \/   / /  ^  \ `---|  |----`|  |__      //////////////////////////////////////////////////
	//   |   ___/  |      /   |  |   \      / /  /_\  \    |  |     |   __|     //////////////////////////////////////////////////
	//   |  |      |  |\  \--.|  |    \    / /  _____  \   |  |     |  |____    //////////////////////////////////////////////////
	//   | _|      | _| `.___||__|     \__/ /__/     \__\  |__|     |_______|   //////////////////////////////////////////////////
	
	function onElementClick() {
		this.edit();
		//return false;
	}
	
	var editing_NBSPFixApplied;

	function startEditing() {
		var self = this;
			
		this.removePlaceholder();
			
		// create replcementElement and add to DOM
		if(!this.replacementElement) {
			var h = this.element.html();
			
			editing_NBSPFixApplied = false;
			if(h.length == 0) {
				h = '&nbsp;'; // add a space to fix a layout problem of the contentditable field.
				editing_NBSPFixApplied = true;
			}
			this.replacementElement = $('<div>').uniqid().html(h);
			this.element.removeClass('x-editable').removeClass('x-editable-on');

			this.replacementElement.css(this.element.css());
			this.replacementElement.css({ 
				'height': 'auto', 
				'min-height': this.element.css('line-height') });
			this.element.addClass('x-editable').addClass('x-editable-on');
			this.element.data(Berta.Editor.DATA_REPLACEMENT, this.replacementElement.attr('id'));
		}
		this.element.after(this.replacementElement);
		this.element.addClass('x-hidden');
		
		// make replacementElement editable
		this.replacementElement.addClass('x-editing');
		this.replacementElement.attr('contentEditable', true);
		this._(enableEditingOptions)(this.replacementElement);
		this.replacementElement.focus();
		
		// init the mechanism to know when the editing has finished
		// set it after a timeout to avoid catching the initial click event
		setTimeout(this._(addFinishTrigger), 1);

		// select all contents
		if (window.getSelection) {// FIREFOX
			var r = document.createRange();
			r.setStart(this.replacementElement[0], 0);
			r.setEnd(this.replacementElement[0], this.replacementElement[0].childNodes.length);
			window.getSelection().addRange(r);
		} else {// SAFARI
			var sel = window.getSelection();
			var r = document.createRange();
			range.selectNodeContents(this.replacementElement[0]);
			sel.removeAllRanges();
			sel.addRange(r);
		}
	}
	function stopEditing() {
		editing_NBSPFixApplied = null;
		this._(removeFinishTrigger)();
		this._(disableEditingOptions)(this.replacementElement);
		this.replacementElement.removeClass('x-editing');
		this.replacementElement.attr('contentEditable', false);
	}
	
	
	
	
	
	
	
	
	
	function onSaveComplete(response) {
		if (response.error) {
			this.askIfCancelOnSaveErorr(response.errorMessage, this._(this.cancel), this._(this.edit));
		} else {
			this.value = response.json.values[this.options.variable];
			this.element.html(this.value);
			
			Berta.Editor.prototype.hidePanelContext.call(this);
			this.fireSave();
			
			// update original value after calling the callback, so the callback can distinguish between the two
			this.originalValue = this.value;
			
			this.cleanup();
		}
	}
	
	
	
	
	
	function addFinishTrigger() {
		// adds click event to the body that checks if the user has clicked outside the replacementElement
		this._onBodyClick = this._(onBodyClick);
		$('html')[0].addEventListener('click', this._onBodyClick, true); // add to capturing phase
		//$(document.body).bind('click' + this.namespace(), this._(onBodyClick));
	}
	function removeFinishTrigger() {
		// adds click event to the body that checks if the user has clicked outside the replacementElement
		$('html')[0].removeEventListener('click', this._onBodyClick, true);
		this._onBodyClick = null;
		//$(document.body).unbind('click' + this.namespace());
	}
	function onBodyClick(event) {
		// captures the click.Berta.Editor.RTE event and checks if the click has happened
		// outside the replacementElement. if yes, then stopEditing()
		var trg = $(event.target);
		//console.debug(this.restVarName, trg, trg.xInPanelOrPopups());
		
		if(this.options.context != 'panel' && trg.xInPanelOrPopups()/*trg.parents('#xBertaPanel').length > 0*/) {
			// clicked on panel while editing outside panel
			// don't touch the event
			return true;
			
		} else {
			// any other case ��we have to stop editing
			event.stopPropagation();
			event.preventDefault();
			var editorId = this.replacementElement.attr('id');
			if(trg.attr('id') != editorId && trg.parents('#' + editorId).length == 0) {
				this.save();
			}
			return false;
		}
	}
	
	
	// EFFECTUATING OPTIONS ...
	
	function enableEditingOptions($el) {
		if(!this.options.pluginOptions.newlines) {
			// Prevents user from adding newlines
			$el.bind('keypress.Berta.Editor.Textline.options.newlines', { that: this }, onKeypressNewlines);
		}
		$el.bind('paste.Berta.Editor.Textline.options.html', { that: this, $el: $el }, onPasteHTMLCheck);
	};
	function disableEditingOptions($el) {
		// remove all listeners attached by enableEditingOptions
		$el.unbind('.Berta.Editor.Textline.options');
		
	};
	
	function onKeypressNewlines(event) {
		//$.log(event.which != 13);
		return event.which != 13; // event is cancelled if enter is pressed
	};
	
	var htmlCheckTimeout;
	function onPasteHTMLCheck(event) {
		var that = event.data.that;
		if(that.options.pluginOptions.tags_allowed !== true) {
			clearTimeout(htmlCheckTimeout);
			htmlCheckTimeout = setTimeout(htmlCheck, 1, event.data.$el, that.options.pluginOptions.tags_allowed);
		}
	}
	function htmlCheck($el, allowedTags) {
		var elHtml = $el.html();
		elHtml = strip_tags(elHtml, allowedTags);
		$el.html(elHtml);
	}
	
	
	
	
	
	
	function strip_tags (str, allowed_tags) {
	    // http://kevin.vanzonneveld.net
	    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: Luke Godfrey
	    // +      input by: Pul
	    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   bugfixed by: Onno Marsman
	    // +      input by: Alex
	    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +      input by: Marc Palau
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +      input by: Brett Zamir (http://brett-zamir.me)
	    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   bugfixed by: Eric Nagel
	    // +      input by: Bobby Drake
	    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   bugfixed by: Tomasz Wesolowski
	    // *     example 1: strip_tags('<p>Kevin</p> <br /><b>van</b> <i>Zonneveld</i>', '<i><b>');
	    // *     returns 1: 'Kevin <b>van</b> <i>Zonneveld</i>'
	    // *     example 2: strip_tags('<p>Kevin <img src="someimage.png" onmouseover="someFunction()">van <i>Zonneveld</i></p>', '<p>');
	    // *     returns 2: '<p>Kevin van Zonneveld</p>'
	    // *     example 3: strip_tags("<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>", "<a>");
	    // *     returns 3: '<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>'
	    // *     example 4: strip_tags('1 < 5 5 > 1');
	    // *     returns 4: '1 < 5 5 > 1'
	
	    var key = '', allowed = false;
	    var matches = [];
	    var allowed_array = [];
	    var allowed_tag = '';
	    var i = 0;
	    var k = '';
	    var html = '';
	
	    var replacer = function (search, replace, str) {
	        return str.split(search).join(replace);
	    };
	
	    // Build allowes tags associative array
	    if (allowed_tags) {
	        allowed_array = allowed_tags.match(/([a-zA-Z0-9]+)/gi);
	    }
	
	    str += '';
	
	    // Match tags
	    matches = str.match(/(<\/?[\S][^>]*>)/gi);
	
	    // Go through all HTML tags
	    for (key in matches) {
	        if (isNaN(key)) {
	            // IE7 Hack
	            continue;
	        }
	
	        // Save HTML tag
	        html = matches[key].toString();
	
	        // Is tag not in allowed list? Remove from str!
	        allowed = false;
	
	        // Go through all allowed tags
	        for (k in allowed_array) {
	            // Init
	            allowed_tag = allowed_array[k];
	            i = -1;
	
	            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
	            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
	            if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag)   ;}
	
	            // Determine
	            if (i == 0) {
	                allowed = true;
	                break;
	            }
	        }
	
	        if (!allowed) {
	            str = replacer(html, "", str); // Custom replace. No regexing
	        }
	    }
	
	    return str;
	};
	
	
}()));



